/**

This file is part of MaCI/GIMnet.

MaCI/GIMnet is free software: you can redistribute it and/or modify it 
under the terms of the GNU Lesser General Public License as published 
by the Free Software Foundation, either version 3 of the License, or 
(at your option) any later version.

MaCI/GIMnet is distributed in the hope that it will be useful, but WITHOUT 
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public 
License for more details.

You should have received a copy of the GNU Lesser General Public 
License along with GIMnet. (See COPYING.LESSER) If not, see 
<http://www.gnu.org/licenses/>.

**/
/**
 * \file
 * \brief Parameter data container header.
 * \author Matthieu Myrsky <matthieu.myrsky@tkk.fi>
 *
 * $Id: ParameterXML.cpp,v 1.3 2009-09-22 08:52:14 morsko Exp $
 *
 */

#include "owndebug.h"
#include "ParameterXML.hpp"
#include <libxml/xmlmemory.h>
#include <libxml/parser.h>
#include <assert.h>

//*****************************************************************************
//*****************************************************************************
using namespace MaCI::Parameter;
//*****************************************************************************
//*****************************************************************************


CParameterXML::CParameterXML(void)
  :iXMLData(),
   iParamType(KUnknown),
   iArraySet(false),
   iParamSet(false),
   iArray(),
   iParam()
{

}
//*****************************************************************************
      
CParameterXML::~CParameterXML(void)
{

}
//*****************************************************************************

bool CParameterXML::EncodeParameterXML(void)
{
  return EncodeParameterXML(iXMLData);
}
//*****************************************************************************

bool CParameterXML::EncodeParameterXML(std::string &aXMLData) 
{
  bool result = true;

  // Clear internal result.
  aXMLData.clear();
  // XML header
  aXMLData += "<?xml version=\"1.0\"?>\n";

  // sqlresult root tag
  aXMLData += "<paramcontainer>\n";
  // Do it!
  switch(iParamType) {
  case KTypeInfoArray:
    result = EncodeInfoArray(aXMLData);
    break;

  case KTypeParam:
    result = EncodeParam(aXMLData);
    break;

  default:
    dPrint(ODERROR,"Container type is Unknown! Will not encode!");
    result = false;
    break; 

  }
  // sqlresult end tag
  aXMLData += "</paramcontainer>\n";

  return result;
}
//*****************************************************************************

void CParameterXML::Reset(void)
{
  iXMLData.clear();
  iArray.clear();
  iArraySet = false;
  iParamSet = false;
  iParamType = KUnknown;
}
//*****************************************************************************

bool CParameterXML::DecodeParameterXML(const std::string &aXMLData)
{
  xmlDocPtr docp;
  xmlNodePtr nodep;
  bool result = false;

  docp = xmlRecoverDoc((xmlChar *) aXMLData.c_str());
  if (docp == NULL) {
    dPrint(ODWARN,"Failed to decode XML doc. Fatal error. Decoding aborted.");
    return false;
  }
  // Get root element
  nodep = xmlDocGetRootElement(docp);
  assert(nodep != NULL);

  // Check that we have a Machine
  if( xmlStrcmp(nodep->name, (xmlChar *) "paramcontainer")) {
    dPrint(ODWARN, "This is not a Parameter XML document (Invalid root node: '%s')",
           nodep->name);
  } else {
    // Enter children level of root.
    nodep = nodep->children;
   
    // parse 
    result = true;

    while(nodep && result) {
     
      if (nodep->type == XML_ELEMENT_NODE) {
        if ( !xmlStrcmp(nodep->name, (xmlChar *) "Info") ) {
          result = DecodeInfoArray(docp, nodep);
        } else if ( !xmlStrcmp(nodep->name, (xmlChar *) "Param") ) {
          result = DecodeParam(docp, nodep);
        } else {
          dPrint(ODERROR,"Unknown tag '%s' in level 0", 
                 nodep->name);
         
        }
      }
      
      // Traverse to next node in level.
      nodep = nodep->next;

    }
  }

  // Free doc.
  if (docp) xmlFreeDoc(docp);


  // Last but not least, if the decoding was succesfull, store the
  // given input XML-data.
  if (result) iXMLData = aXMLData;

  return result;
}
//*****************************************************************************

void CParameterXML::SetParameterInfoArray(TParameterInfoArray aParameterInfoArray)
{
  iParamType = KTypeInfoArray;
  iArray = aParameterInfoArray;
  iArraySet = true;

}
//*****************************************************************************

void CParameterXML::SetParameter(TParam aParam)
{
  iParamType = KTypeParam;
  iParam = aParam;
  iParamSet = true;
}
//*****************************************************************************

bool CParameterXML::GetParameters(TParameterInfoArray &aParameterInfoArray)
{
  if(iArraySet)  aParameterInfoArray = iArray;
  return iArraySet;

}
//*****************************************************************************

bool CParameterXML::GetParameter(TParam &aParam)
{
  if(iParamSet)  aParam = iParam;
  return iParamSet;
}
//*****************************************************************************

void CParameterXML::PrintDecodedData(unsigned int level)
{
  dPrint(level,"%s",iXMLData.c_str());
  
}
//*****************************************************************************

bool CParameterXML::EncodeInfoArray(std::string &aXMLData)
{
  bool result = iArraySet;
  if(iArraySet){
    for(unsigned int i = 0 ; i< iArray.size(); i++){
      aXMLData += "  <Info>\n";
      // Got value (can be empty string)
      aXMLData += "    <key>" +iArray[i].key + "</key>\n";
      aXMLData += "    <description>" +iArray[i].description + "</description>\n";
      aXMLData += "    <currentValue>" +iArray[i].currentValue + "</currentValue>\n";
      aXMLData += "    <validValues>" + iArray[i].validValues + "</validValues>\n";
      aXMLData += "    <validRegExp>" + iArray[i].validValuesRegExp+ "</validRegExp>\n";
      aXMLData += "  </Info>\n";
    }
  }
  
  return result;

}
//*****************************************************************************

bool CParameterXML::EncodeParam(std::string &aXMLData)
{
  bool result = iParamSet;
  
  if(result){
    aXMLData += "  <Param>\n";
    aXMLData += "    <key>" +iParam.key + "</key>\n"; 
    aXMLData += "    <value>"+iParam.value+"</value>\n";
    aXMLData += "  </Param>\n";
  }
  


  return result;
}
//*****************************************************************************

bool CParameterXML::DecodeInfoArray(xmlDocPtr docp, xmlNodePtr nodep)
{
  bool result = true;
  std::string key ="",description="",currentValue="",validValues="",validRegExp="";
  // Take children
  xmlNodePtr subnodep = nodep->children;
  // Iterate children.
  while(subnodep && result) {
    if (subnodep->type == XML_ELEMENT_NODE) {
      if( !xmlStrcmp(subnodep->name, (xmlChar *) "key")){
        xmlChar *content = xmlNodeListGetString(docp, subnodep->xmlChildrenNode, 0);
        if(content){
          key = std::string((const char*) content);
          dPrint(15,"key : '%s'",key.c_str());
          xmlFree(content);
        }
        
      }else if(!xmlStrcmp(subnodep->name, (xmlChar *) "description")){
        xmlChar *content = xmlNodeListGetString(docp, subnodep->xmlChildrenNode, 0);
        if(content){
          description = std::string((const char*) content);
          dPrint(15,"description : '%s'",description.c_str());
          xmlFree(content);
        }
      }else if(!xmlStrcmp(subnodep->name, (xmlChar *) "currentValue")){
        xmlChar *content = xmlNodeListGetString(docp, subnodep->xmlChildrenNode, 0);
        if(content){
          currentValue = std::string((const char*) content);
          dPrint(15,"currentvalues : '%s'",currentValue.c_str());
          xmlFree(content);
        }
      }else if(!xmlStrcmp(subnodep->name, (xmlChar *) "validValues")){
        xmlChar *content = xmlNodeListGetString(docp, subnodep->xmlChildrenNode, 0);
        if(content){
          validValues = std::string((const char*) content);
          dPrint(15,"validValues : '%s'",validValues.c_str());
          xmlFree(content);
        }
      }else if(!xmlStrcmp(subnodep->name, (xmlChar *) "validRegExp")){
        xmlChar *content = xmlNodeListGetString(docp, subnodep->xmlChildrenNode, 0);
        if(content){
          validRegExp = std::string((const char*) content);
          dPrint(15,"validRegExp : '%s'",validRegExp.c_str());
          xmlFree(content);
        }
        //Last parameter, so save data
        TParameterInfo info(key,
                            description,
                            currentValue,
                            validValues,
                            validRegExp);
        iArray.push_back(info);
        iArraySet = true;
        //Finally clear all strings
        key.clear();description.clear();currentValue.clear();validValues.clear();validRegExp.clear();
      }else{
        dPrint(1,"Didn't recognize key '%s'. Decoding failed!",subnodep->name);
        result = false;
      }
        
    }
    // Traverse to next node in level
   
    subnodep = subnodep->next;

   
  }
  
 
   return result;
}
//*****************************************************************************

bool CParameterXML::DecodeParam(xmlDocPtr docp, xmlNodePtr nodep)
{
  dPrint(1,"DecodeParam called");
  bool result = true;
  std::string key ="",value="";
  // Take children
  xmlNodePtr subnodep = nodep->children;
  // Iterate children.
  while(subnodep && result) {
    if (subnodep->type == XML_ELEMENT_NODE) {
      if( !xmlStrcmp(subnodep->name, (xmlChar *) "key")){
        xmlChar *content = xmlNodeListGetString(docp, subnodep->xmlChildrenNode, 0);
        if(content){
          key = std::string((const char*) content);
          dPrint(15,"key : '%s'",key.c_str());
          xmlFree(content);
        }
        
      }else if(!xmlStrcmp(subnodep->name, (xmlChar *) "value")){
        xmlChar *content = xmlNodeListGetString(docp, subnodep->xmlChildrenNode, 0);
        if(content){
          value = std::string((const char*) content);
          dPrint(15,"value : '%s'",value.c_str());
          xmlFree(content);
        }
      
        //Last parameter, so save data
        TParam param(key,
                     value);
        iParam = param;
        iParamSet = true;
        //Finally clear all strings
        key.clear();value.clear();
      }else{
        dPrint(1,"Didn't recognize key '%s'. Decoding failed!",subnodep->name);
        result = false;
      }
        
    }
    // Traverse to next node in level
   
    subnodep = subnodep->next;

   
  }
  
 
   return result;
}
//*****************************************************************************
//*****************************************************************************
//*****************************************************************************
//*****************************************************************************
//*****************************************************************************
//*****************************************************************************
//*****************************************************************************
//*****************************************************************************
//*****************************************************************************
